<?php

namespace yunj\core\traits;

use yunj\core\enum\Enum;

trait RedisKey {

    /**
     * 参数集合
     * @var array
     */
    private $args = [];

    /**
     * 设置参数集合
     * @param ...$args
     * @return static
     */
    public function setArgs(...$args) {
        $this->args = $args ?: [];
        return $this;
    }

    /**
     * 获取参数集合
     * @return array
     */
    public function getArgs(): array {
        return $this->args && isset($this->args) ? $this->args : [];
    }

    /**
     * 获取完整的key。示例：RedisKey::ADMIN_MEMBER_ID_BY_TOKEN()->setArgs($token)->key()
     * @return string
     */
    public function key(): string {
        return $this->_key();
    }

    // 获取完整的key。默认方法
    protected function _key(): string {
        /** @var Enum $this */
        $key = redis_full_key($this->getValue());
        $keySuffixCall = $this->getAttr('keySuffixCall');
        $args = $this->getArgs();
        if (is_callable($keySuffixCall)) {
            $key .= call_user_func_array($keySuffixCall, $args);
        } else if ($args) {
            $key .= md5(json_encode(ksort($args)));
        }
        return $key;
    }

    /**
     * 获取缓存值,自动延长缓存时间。示例：RedisKey::ADMIN_MEMBER_ID_BY_TOKEN()->setArgs($token)->getCacheValue(60)
     * @param int $ttl 延长时间（0 不延长）
     * @param bool $autoExtend 自动延长过期时间（为true且redis值存在时，自动延长缓存时间）
     * @return string|array|bool|mixed
     */
    public function getCacheValue(int $ttl = 0, bool $autoExtend = false) {
        /** @var Enum $this */
        // 此处防止redis服务失效
        try {
            $redis = redis();
            $key = $this->key();
            $res = $redis->get($key);
            // 值存在时
            if ($res !== false && $res !== null) {
                // 自动延长过期时间
                if ($autoExtend && $ttl > 0) {
                    $this->setCacheValue($res, $ttl);
                }
                if (is_json($res,$resData,true)) {
                    $res = $resData;
                }
                return $res;
            }
        } catch (\Throwable $e) {
            log_exception($e);
            $redis = null;
        }
        // 重新获取值
        $valueCall = $this->getAttr('valueCall');
        if (!is_callable($valueCall)) return false;
        $args = $this->getArgs();
        $res = call_user_func_array($valueCall, $args);
        if ($res === false || $res === null || (!is_array($res) && !is_scalar($res))) return false;
        // 设置过期时间
        if ($redis && $ttl > 0) $this->setCacheValue($res, $ttl);
        return $res;
    }

    /**
     * 设置缓存值。示例：RedisKey::ADMIN_MEMBER_ID_BY_TOKEN()->setArgs($token)->setCacheValue($value,60)
     * @param int|string|float|double|array $value
     * @param false|int $ttl 有效时间（0 表示默认为系统）
     * @return bool
     */
    public function setCacheValue($value, $ttl = 0) {
        try {
            if (is_array($value)) $value = json_encode($value, JSON_UNESCAPED_UNICODE);
            if (!is_scalar($value)) return false;
            $redis = redis();
            $key = $this->key();
            if ($ttl > 0) {
                $res = $redis->setex($key, $ttl, $value);
            } else {
                $res = $redis->set($key, $value);
            }
        } catch (\Throwable $e) {
            log_exception($e);
            $res = false;
        }
        return $res;
    }

    /**
     * 删除缓存值。示例：RedisKey::ADMIN_MEMBER_ID_BY_TOKEN()->setArgs($token)->delCacheValue()
     * @param bool $all 是否删除所有，对于有后缀变化的key适用
     * @return int
     */
    public function delCacheValue($all = false): int {
        try {
            $redis = redis();
            if ($all && ($keySuffixCall = $this->getAttr('keySuffixCall')) && is_callable($keySuffixCall)) {
                $pattern = redis_full_key($this->getValue()) . '*';
                $keys = redis_keys($pattern);
            } else {
                $keys = $this->key();
            }
            return $redis->del($keys);
        } catch (\Throwable $e) {
            log_exception($e);
            return 0;
        }
    }

}
